package com.rabbithelper.handle;

import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONArray;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

import com.rabbithelper.constant.SyncOperationType;
import com.rabbithelper.entity.*;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

public class MessageHandler {

    @Autowired
    private SycnHandler sycnHandler;

    public void handleUserInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysUser.class,
                sycnHandler::SycnSaveUser, sycnHandler::SycnUpdateUser, sycnHandler::SycnDeleteUser);
    }

    public void handlePostInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysPost.class,
                sycnHandler::SycnSavePost, sycnHandler::SycnUpdatePost, sycnHandler::SycnDeletePost);
    }

    public void handleRoleInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysRole.class,
                sycnHandler::SycnSaveRole, sycnHandler::SycnUpdateRole, sycnHandler::SycnDeleteRole);
    }

    public void handleMenuInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysMenu.class,
                sycnHandler::SycnSaveMenu, sycnHandler::SycnUpdateMenu, sycnHandler::SycnDeleteMenu);
    }

    public void handleDeptInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysDept.class,
                sycnHandler::SycnSaveDept, sycnHandler::SycnUpdateDept, sycnHandler::SycnDeleteDept);
    }

    public void handleUserRoleInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleAssociationMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysUserRole.class,
                sycnHandler::syncSaveUserRole, sycnHandler::syncUpdateUserRole, sycnHandler::syncDeleteUserRole);
    }

    public void handleUserDeptInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleAssociationMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysUserDept.class,
                sycnHandler::syncSaveUserDept, sycnHandler::syncUpdateUserDept, sycnHandler::syncDeleteUserDept);
    }

    public void handleUserPostInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleAssociationMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysUserPost.class,
                sycnHandler::syncSaveUserPost, sycnHandler::syncUpdateUserPost, sycnHandler::syncDeleteUserPost);
    }

    public void handleRoleMenuInfo(String messageBody, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        handleAssociationMessage(messageBody, deliveryTag, channel, SyncOperationType::getValue, SysRoleMenu.class,
                sycnHandler::syncSaveRoleMenu, sycnHandler::syncUpdateRoleMenu, sycnHandler::syncDeleteRoleMenu);
    }

    /**
     * 处理实体消息
     */
    public <T> void handleMessage(String messageBody, long deliveryTag, Channel channel,
                                  Function<SyncOperationType, String> getTypeFunction,
                                  Class<T> clazz,
                                  Consumer<List<T>> saveHandler,
                                  Consumer<List<T>> updateHandler,
                                  Consumer<List<String>> deleteHandler) {
        handleMessageInternal(messageBody, deliveryTag, channel, getTypeFunction, clazz,
                saveHandler, updateHandler, (List<T> data) -> deleteHandler.accept((List<String>) data));
    }
    /**
     * 处理关联消息
     */
    public <T> void handleAssociationMessage(String messageBody, long deliveryTag, Channel channel,
                                             Function<SyncOperationType, String> getTypeFunction,
                                             Class<T> clazz,
                                             Consumer<List<T>> saveHandler,
                                             Consumer<List<T>> updateHandler,
                                             Consumer<List<T>> deleteHandler) {
        handleMessageInternal(messageBody, deliveryTag, channel, getTypeFunction, clazz,
                saveHandler, updateHandler, deleteHandler);
    }

    /**
     * 处理消息内部逻辑
     */

    private <T> void handleMessageInternal(String messageBody, long deliveryTag, Channel channel,
                                           Function<SyncOperationType, String> getTypeFunction,
                                           Class<T> clazz,
                                           Consumer<List<T>> saveHandler,
                                           Consumer<List<T>> updateHandler,
                                           Consumer<List<T>> deleteHandler) {
        try {
            JSONObject jsonObject = JSONUtil.parseObj(messageBody);
            String operationType = jsonObject.getStr("operationType");
            JSONArray dataArray = jsonObject.getJSONArray("data");

            List<?> data;
            if (getTypeFunction.apply(SyncOperationType.ADD).equals(operationType)) {
                data = JSONUtil.toList(dataArray, clazz);
                saveHandler.accept((List<T>) data);
            } else if (getTypeFunction.apply(SyncOperationType.UPDATE).equals(operationType)) {
                data = JSONUtil.toList(dataArray, clazz);
                updateHandler.accept((List<T>) data);
            } else if (getTypeFunction.apply(SyncOperationType.DELETE).equals(operationType)) {
                data = JSONUtil.toList(dataArray, String.class);
                deleteHandler.accept((List<T>) data); // 注意这里的类型转换
            } else {
                throw new IllegalArgumentException("类型错误");
            }
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            handleError(e, deliveryTag, channel);
        }
    }

    /**
     * 处理错误
     */
    private void handleError(Exception e, long deliveryTag, Channel channel) {
        try {
            channel.basicNack(deliveryTag, false, true); // true 表示重新入队
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        e.printStackTrace();
    }

}